﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace Irrlicht.Net.Video
{
    public class Texture : ReferenceCounted
    {
        /// <summary>
        /// Flag for EMT_ONETEXTURE_BLEND, ( BlendFactor ) BlendFunc = source * sourceFactor + dest * destFactor
        /// </summary>
        public enum BlendFactors	
        {
            /// <summary>
            /// src & dest	(0, 0, 0, 0)
            /// </summary>
            Zero	= 0,
       
            /// <summary>
            /// src & dest	(1, 1, 1, 1)
            /// </summary>
            One,
        
            /// <summary>
            /// src	(destR, destG, destB, destA)
            /// </summary>
            DstColor,
        
            /// <summary>
            /// src	(1-destR, 1-destG, 1-destB, 1-destA)
            /// </summary>
            OneMinusDstColor,
        
            /// <summary>
            /// dest	(srcR, srcG, srcB, srcA)
            /// </summary>
            SrcColor,
        
            /// <summary>
            /// dest	(1-srcR, 1-srcG, 1-srcB, 1-srcA)
            /// </summary>
            OneMinusSrcColor,
        
            /// <summary>
            /// src & dest	(srcA, srcA, srcA, srcA)
            /// </summary>
            SrcAlpha,
        
            /// <summary>
            /// src & dest	(1-srcA, 1-srcA, 1-srcA, 1-srcA)
            /// </summary>
            OneMinusSrcAlpha,
        
            /// <summary>
            /// src & dest	(destA, destA, destA, destA)
            /// </summary>
            DstAlpha,
        
            /// <summary>
            /// src & dest	(1-destA, 1-destA, 1-destA, 1-destA)
            /// </summary>
            OneMinusDstAlpha,
        
            /// <summary>
            /// src	(min(srcA, 1-destA), idem, ...)
            /// </summary>
            SrcAlphaSaturate
        };
	
        /// <summary>
        /// MaterialTypeParam: e.g. DirectX: D3DTOP_MODULATE, D3DTOP_MODULATE2X, D3DTOP_MODULATE4X
        /// </summary>
        public enum ModulateFunctions	
        {		           
            Modulate1x	= 1,		
            Modulate2x	= 2,		
            Modulate4x	= 4	
        };
        
        /// <summary>
        /// Comparison function, e.g. for depth buffer test
        /// </summary>
        public enum ComparisonFunctions
	    {
            /// <summary>
            /// Test never succeeds, this equals disable
            /// </summary>
            Never=0,
		
            /// <summary>
            /// <= test, default for e.g. depth test
            /// </summary>
            LessEqual=1,

            /// <summary>
            /// Exact equality
            /// </summary>
            Equal=2,

            /// <summary>
            /// exclusive less comparison, i.e. <
            /// </summary>
            Less,
		
            /// <summary>
            /// Succeeds almost always, except for exact equality
            /// </summary>
            NotEqual,

            /// <summary>
            /// >= test
            /// </summary>
            GreaterEqual,
		
            /// <summary>
            /// inverse of <=
            /// </summary>
            Greater,
		
            /// <summary>
            /// test succeeds always
            /// </summary>
            Always
        };

        /// <summary>
        /// Enum values for enabling/disabling color planes for rendering
        /// </summary>
        public enum ColorPlanes	
        {
            /// <summary>
            /// No color enabled
            /// </summary>
            None=0,
		
            /// <summary>
            /// Alpha enabled
            /// </summary>
            Alpha=1,

            /// <summary>
            /// Red enabled
            /// </summary>
            Red=2,
		
            /// <summary>
            /// Green enabled
            /// </summary>
            Green=4,
		
            /// <summary>
            /// Blue enabled
            /// </summary>
            Blue=8,
		
            /// <summary>
            /// All colors, no alpha
            /// </summary>
            Rgb=14,
		
            /// <summary>
            /// All planes enabled
            /// </summary>
            All=15
        };

        /// <summary>
        /// Source of the alpha value to take
        /// </summary>
        /// <remarks>
        /// This is currently only supported in EMT_ONETEXTURE_BLEND. You can use an
        /// or'ed combination of values. Alpha values are modulated (multiplicated).
        /// </remarks>
        public enum AlphaSources
        {
            /// <summary>
            /// Use no alpha, somewhat redundant with other settings
            /// </summary>
            None=0,
		
            /// <summary>
            /// Use vertex color alpha
            /// </summary>
            VertexColor,
		
            /// <summary>
            /// Use texture alpha channel
            /// </summary>
            Texture
        };

        /// <summary>
	    /// These flags are used to specify the anti-aliasing and smoothing modes
    	/// </summary>
        /// <remarks>
        /// Techniques supported are multisampling, geometry smoothing, and alpha
    	/// to coverage.
	    /// Some drivers don't support a per-material setting of the anti-aliasing
    	/// modes. In those cases, FSAA/multisampling is defined by the device mode
	    /// chosen upon creation via irr::SIrrCreationParameters.
        /// </remarks>
        public enum AntiAliasingModes
	    {
            /// <summary>
            /// Use to turn off anti-aliasing for this material
            /// </summary>
            Off=0,

            /// <summary>
            /// Default anti-aliasing mode
            /// </summary>
            Simple=1,

            /// <summary>
            /// High-quality anti-aliasing, not always supported, automatically enables SIMPLE mode
            /// </summary>
            Quality=3,

            /// <summary>
            /// Line smoothing
            /// </summary>
            LineSmooth=4,

            /// <summary>
            /// point smoothing, often in software and slow, only with OpenGL
            /// </summary>
            PointSmooth=8,

            /// <summary>
            /// All typical anti-alias and smooth modes
            /// </summary>
            FullBasic=15,

            /// <summary>
            /// Enhanced anti-aliasing for transparent materials
            /// </summary>
            /// <remarks>
            /// Usually used with EMT_TRANSPARENT_ALPHA_REF and multisampling.
            /// </remarks>
            AlphaToCoverage=16
	    };


        /// <summary>
        /// These flags allow to define the interpretation of vertex color when lighting is enabled
        /// </summary>
        /// <remarks>
        /// Without lighting being enabled the vertex color is the only value defining the fragment color.
        /// Once lighting is enabled, the four values for diffuse, ambient, emissive, and specular take over.
        /// With these flags it is possible to define which lighting factor shall be defined by the vertex color
        /// instead of the lighting factor which is the same for all faces of that material.
        /// The default is to use vertex color for the diffuse value, another pretty common value is to use
        /// vertex color for both diffuse and ambient factor.
        /// </remarks>
        public enum ColorMaterials
        {
            /// <summary>
            /// Don't use vertex color for lighting
            /// </summary>
            None=0,

            /// <summary>
            /// Use vertex color for diffuse light, this is default
            /// </summary>
            Diffuse,

            /// <summary>
            /// Use vertex color for ambient light
            /// </summary>
            Ambient,

            /// <summary>
            /// Use vertex color for emissive light
            /// </summary>
            Emissive,

            /// <summary>
            /// Use vertex color for specular light
            /// </summary>
            Specular,

            /// <summary>
            /// Use vertex color for both diffuse and ambient light
            /// </summary>
            DiffuseAndAmbient
        };

        public Texture(IntPtr pointer)
            : base(pointer)
        {
        }

        /// <summary>
        /// EMT_ONETEXTURE_BLEND: pack srcFact, dstFact, Modulate and alpha source to MaterialTypeParam
        /// </summary>
        /// <remarks>
        /// alpha source can be an OR'ed combination of E_ALPHA_SOURCE values.
        /// </remarks>
        /// <param name="srcFact">Source Blend factors</param>
        /// <param name="dstFact">Destination Blend factors</param>
        /// <param name="modulate">Modulate funtions</param>
        /// <param name="alphaSource">Alpha Source</param>
        /// <returns>Packed texture blending function as float</returns>
        public float PackTexureBlendFunctions(BlendFactors srcFact, BlendFactors dstFact, ModulateFunctions modulate,  AlphaSources alphaSource)
	    {
            uint tmp = ((uint) alphaSource << 12) | ((uint) modulate << 8) | ((uint) srcFact << 4) | (uint) dstFact;		
            return Convert.ToSingle(tmp);
	    }
        //=EMFN_MODULATE_1X
          //  =EAS_TEXTURE 

        /// <summary>
        /// EMT_ONETEXTURE_BLEND: pack srcFact, dstFact, Modulate and alpha source to MaterialTypeParam
        /// Alpha Source defaults to Texture.
        /// </summary>
        /// <param name="srcFact">Source Blend factors</param>
        /// <param name="dstFact">Destination Blend factors</param>
        /// <param name="modulate">Modulate funtions</param>
        /// <returns>Packed texture blending function as float</returns>
        public float PackTexureBlendFunctions(BlendFactors srcFact, BlendFactors dstFact, ModulateFunctions modulate)
        {
            return PackTexureBlendFunctions(srcFact, dstFact, modulate, AlphaSources.Texture);
        }

        /// <summary>
        /// EMT_ONETEXTURE_BLEND: pack srcFact, dstFact, Modulate and alpha source to MaterialTypeParam
        /// Alpha Source defaults to Texture.  Modulate Function defaults to 1x.
        /// </summary>
        /// <param name="srcFact">Source Blend factors</param>
        /// <param name="dstFact">Destination Blend factors</param>
        /// <returns>Packed texture blending function as float</returns>
        public float PackTexureBlendFunctions(BlendFactors srcFact, BlendFactors dstFact)
        {
            return PackTexureBlendFunctions(srcFact, dstFact, ModulateFunctions.Modulate1x, AlphaSources.Texture);
        }
	
        /// <summary>
        /// EMT_ONETEXTURE_BLEND: unpack srcFact & dstFact and Modulo to MaterialTypeParam
        /// </summary>
        /// <remarks>
        /// The fields don't use the full byte range, so we could pack even more...
        /// </remarks>
        /// <param name="srcFact"></param>
        /// <param name="dstFact"></param>
        /// <param name="modulo"></param>
        /// <param name="alphaSource"></param>
        /// <param name="param"></param>
        void unpack_texureBlendFunc(BlendFactors srcFact, BlendFactors dstFact, ModulateFunctions modulo, AlphaSources alphaSource, float param)
	    {
	    	uint state = Convert.ToUInt32(param);
		    alphaSource = (AlphaSources)((state & 0x0000F000u) >> 12);
    		modulo	= (ModulateFunctions)((state & 0x00000F00u) >> 8);
	    	srcFact = (BlendFactors)((state & 0x000000F0u) >> 4);
            dstFact = (BlendFactors)((state & 0x0000000Fu));
	    }

        /// <summary>
        /// EMT_ONETEXTURE_BLEND: has BlendFactor Alphablending
        /// </summary>
        /// <param name="factor">Blend factors</param>
        /// <returns>true if alpha blended</returns>
	    bool textureBlendFunc_hasAlpha (BlendFactors factor)
	    {
		    switch (factor)
		    {
                case BlendFactors.SrcAlpha:
                case BlendFactors.OneMinusSrcAlpha:
                case BlendFactors.DstAlpha:
                case BlendFactors.OneMinusDstAlpha:
                case BlendFactors.SrcAlphaSaturate:
                    {
                        return true;
                    }
                default:
                    {
                        return false;
                    }
		    }
	    }
    }
}
